
#include "SPI.h"
#include "flash.h"
#include <string.h>

void flash_init(void) { SPI_init(); }

byte flash_status() {
    byte read_status_register1_ins = 5;
    byte register1_data = 0;
    SPI_rw(&register1_data, 1, &read_status_register1_ins, 1);
    return register1_data;
}

// ins length == 3
static void address_into_ins(byte ins[], int address) {

    ins[2] = 0xFF & address;
    ins[1] = 0xFF & address >> 8;
    ins[0] = 0xFF & address >> 16;
}

void flash_read(int address, __out__ byte rd[], int len) {

    // instruction for read
    // 指令 + 地址
    byte ins[4] = {0};
    ins[0] = 3;
    // ins[3] = 0xFF & address;
    // ins[2] = 0xFF & address >> 8;
    // ins[1] = 0xFF & address >> 16;
    // set address
    address_into_ins(ins + 1, address);
    // p();
    // p_barr(ins, 4);
    SPI_rw(rd, len, ins, 4);
}

// 1.erase
// 2.write data
// flash 1 => 0
// max data 256 byte to write
// erase 4KB then to write data
// 先擦除在写数据，之前的数据会丢失
void flash_write0(int address, __in__ byte wd[], int len) {

    // instruction for write
    // 指令 + 地址
    byte ins[4 + 256] = {0};
    // write enable
    ins[0] = 6;
    SPI_rw(null, 0, ins, 1);
    // p();
    // p_barr(ins, 1);
    // erase sector 4kb
    ins[0] = 0x20;
    // ins[3] = 0xFF & address;
    // ins[2] = 0xFF & address >> 8;
    // ins[1] = 0xFF & address >> 16;
    address_into_ins(ins + 1, address);
    SPI_rw(null, 0, ins, 4);
    // p();
    // busy
    while (flash_status() & 1)
        ;
    // p();
    // write enable
    ins[0] = 6;
    SPI_rw(null, 0, ins, 1);

    // input program
    // write data
    ins[0] = 2;
    // set address
    // ins[3] = 0xFF & address;
    // ins[2] = 0xFF & address >> 8;
    // ins[1] = 0xFF & address >> 16;
    address_into_ins(ins + 1, address);
    // copy data to ins
    memcpy(ins + 4, wd, len);
    SPI_rw(null, 0, ins, len + 4);

    // check status and wait to over write
    // busy
    while (flash_status() & 1)
        ;
}

// 写入一字节
void flash_write_byte(int address, __in__ byte data) {

    flash_write(address, &data, 1);
}

// 读取一字节
byte flash_read_byte(int address) {
    byte data = 0;
    // p_barr(&data, 1);
    flash_read(address, &data, 1);
    // p_barr(&data, 1);
    return data;
}

static void erase_sector(int start_sector_address) {
    // instruction for write
    // 指令 + 地址
    byte ins[4] = {0};
    // write enable
    ins[0] = 6;
    SPI_rw(null, 0, ins, 1);
    // p();
    // p_barr(ins, 1);
    // erase sector 4kb
    ins[0] = 0x20;
    // ins[3] = 0xFF & address;
    // ins[2] = 0xFF & address >> 8;
    // ins[1] = 0xFF & address >> 16;
    address_into_ins(ins + 1, start_sector_address);
    SPI_rw(null, 0, ins, 4);
    // p();
    // busy
    while (flash_status() & 1)
        ;
}

// page 256 bytes
//  256 bytes per write
static void write_page(int start_page_address, __in__ byte d[], int len) {
    // instruction for write
    // 一次性最多写入256字节
    byte ins[4 + 256] = {0};
    // write enable
    ins[0] = 6;
    SPI_rw(null, 0, ins, 1);

    // input program
    // write data
    ins[0] = 2;
    // set address
    address_into_ins(ins + 1, start_page_address);
    // copy data to ins
    memcpy(ins + 4, d, len);
    SPI_rw(null, 0, ins, len + 4);

    // check status and wait to over write
    // busy
    while (flash_status() & 1)
        ;
}

// static void init_byte_FF(byte _4KB_[4 * 1024]) {
//     // init byte FF
//     for (int i = 0; i < 4 * 1024; i++) {
//         _4KB_[i] = -1;
//     }
// }

// 为了任意位置写入数据不丢失 new API
// 4 MB max
// 数据会覆盖以前地址上的数据，以后写文件API的时候要注意文件隔离，覆盖文件报错
void flash_write(int address, __in__ byte data[], int len) {

    // erase 4kb
    // only 256 bytes per write
    // RAM << 4MB inner flash only 64KB
    // 20KB的SRAM
    // 存储数据的时候不要管大小，存放数据的大小只能由调用者注意不要越界了！

    // int _4MB = 4 * 1024 * 1024;
    int _4KB = 4 * 1024;
    int start_sector = address / _4KB;
    int end_sector = (address + len) / _4KB;
    // int total_sectors = end_sector - start_sector + 1;
    // p();
    byte _4KB_[4 * 1024] = {0};

    // p();

    int data_index = 0;
    // 读一个sector就写一个sector
    for (int i = start_sector; i <= end_sector; i++) {
        int start_sector_address = i * _4KB;
        // flash会自动读取FF，不用初始化
        flash_read(start_sector_address, _4KB_, _4KB);
        // p();
        // erase 4KB
        erase_sector(start_sector_address);
        // p();

        int index_in_4KB = 0;
        if (address > start_sector_address) {
            // % 4kb same as below
            index_in_4KB = address - start_sector_address;
        }

        // write data into the sector
        for (int j = index_in_4KB; j < _4KB && data_index < len;
             j++, data_index++) {
            _4KB_[j] = data[data_index];
        }
        // max 256 bytes per write
        // 4KB / 256 一定整除！
        // 因为擦出了4KB，必须写入4KB，否则data前后的数据会丢
        for (int j = 0; j < _4KB; j += 256) {
            write_page(start_sector_address + j, _4KB_ + j, 256);
        }
    }
}

void flash_clear_sector(int address) {
    int _4KB = 4 * 1024;
    // 注意整除
    int start_sector_address = address / _4KB * _4KB;
    erase_sector(start_sector_address);
}

void flash_remove(int address, int len) {
    // erase 4kb
    // only 256 bytes per write
    // RAM << 4MB inner flash only 64KB
    // 20KB的SRAM
    // 存储数据的时候不要管大小，存放数据的大小只能由调用者注意不要越界了！

    // int _4MB = 4 * 1024 * 1024;
    int _4KB = 4 * 1024;
    int start_sector = address / _4KB;
    int end_sector = (address + len) / _4KB;
    // int total_sectors = end_sector - start_sector + 1;
    // p();
    byte _4KB_[4 * 1024] = {0};

    // p();

    int data_index = 0;
    // 读一个sector就写一个sector
    for (int i = start_sector; i <= end_sector; i++) {
        int start_sector_address = i * _4KB;
        // flash会自动读取FF，不用初始化
        flash_read(start_sector_address, _4KB_, _4KB);
        // p();
        // erase 4KB
        erase_sector(start_sector_address);
        // p();

        int index_in_4KB = 0;
        if (address > start_sector_address) {
            // % 4kb same as below
            index_in_4KB = address - start_sector_address;
        }

        // write data into the sector
        for (int j = index_in_4KB; j < _4KB && data_index < len;
             j++, data_index++) {
            _4KB_[j] = 0xFF; // 0xFF
        }
        // max 256 bytes per write
        // 4KB / 256 一定整除！
        // 因为擦出了4KB，必须写入4KB，否则data前后的数据会丢
        for (int j = 0; j < _4KB; j += 256) {
            write_page(start_sector_address + j, _4KB_ + j, 256);
        }
    }
}

// return n bytes
int flash_capacity() {
    byte ins = 0x9F;
    byte data[3] = {0};
    SPI_rw(data, 3, &ins, 1);
    // p_barr(data, 3);
    return 1 << data[2];
}
